<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      function Person(name) {
        this.name = name
      }
      //创建p1对象，p1本身有一个name属性
      let p1 = new Person('a')
      //创建p2对象，p2本身也有一个name属性
      let p2 = new Person('b')
      //上面的2个对象p1和p2已经跟一个对象建立关系
      //跟p1和p2建立关系的对象是函数Person的一个属性指向的对象
      //也就是prototype属性指向的对象

      Person.prototype.age = 18
      //此处是原型，在原型中创建age属性
      console.log(p1.age)
      //输出18
      console.log(p2.age)
      //输出18

      //两者之间怎么建立关系的，什么时候建立关系
      //通过new Person()时创建对象，会在每一个对象比如(p1,p2)里偷偷的添加属性，名字叫__proto__，它的值就是指向构造线函数prototype属性指向的对象
      console.log(Person.prototype)
      //输出原型age为18，构造器输出Perosn
      console.log(Person.prototype.constructor === Person)
      //判断Person的原型和构造器是否指向本身
      console.log(p1.__proto__)
      //原型输出age：18，构造器指向Person __proto__指向Object
      console.log(p1.__proto__ === Person.prototype)
      //判断p1是否等于Person的原型对象
      console.log(p2.__proto__ === Person.prototype)
      //判断p2是否等于Person的原型对象

      p1.name = 'aaa'
      console.log(p1.name)
      console.log(p2.name)
      //只修改了p1却没有修改p2，两者都是继承原型对象，p1.name是本身的属性，可以进行修改，没有修改原型对象，如果使用Person.prototype.name进行修改，p1,p2都会修改成功

      Person.prototype.age = 90
      console.log(p1.age)
      console.log(p2.age)
      //Person.prototype.age是在原型对象中创建的，原型对象age修改了，继承的对象也会进行age的修改

      //高阶部分
      function Student() {}
      console.log(Student.prototype)
      //constructor指向函数Student，隐式__proto__指向Object，原型链会在调用对象时查看是否有这个属性，如果没有则查找原型对象，原型对象中没有则会一直查找直到顶部Object.prototype
      console.log(Student.prototype.constructor)
      //指向函数Student本身
      //指向：函数--->prototype---->原型对象----->constructor----->函数
      Student.prototype = { name: 'abc' }
      //改变Student的原型对象指向

      let s = new Student()
      console.log(s.name)
      //指向：函数---->原型属性：prototype----->原型对象------>name:'abc'
      console.log(Student.prototype.constructor)
      //指向Object
      //指向：函数----->原型属性：prototype------->原型对象------->name:'abc'------->constructor----->Object

      let o = {}
      console.log(o.constructor)
      //对象字面量最终指向Object
      //指向Object

      //结论：尽量不要改变构造函数的原型对象
      //如果改了(像58行的代码所示),就一定要改回constructor对的指向
      //指向修改之后
      Student.prototype.constructor = Student
      console.log(Student.prototype.constructor)
      //第三部分：尽量将公共的东西，放在原型对象中，像方法基本会放到原型对象中
      function Emp(name) {
        this.name = name
      }
      Emp.prototype.work = function () {
        console.log('原型this的指向：', this)
        console.log(this.name + '在编程。。。')
      }
      //指向的是创建出来的对象，比如下列代码
      let e = new Emp('m')
      e.work()
    </script>
  </body>
</html>
